package com.nuoniu.sibanyun.service.production.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.nuoniu.sibanyun.common.exception.NuoNiuException;
import com.nuoniu.sibanyun.entity.bo.VoucherDetailBo;
import com.nuoniu.sibanyun.entity.bo.VoucherMainBo;
import com.nuoniu.sibanyun.entity.bo.VoucherSearchBo;
import com.nuoniu.sibanyun.entity.erp.ErpNumberSet;
import com.nuoniu.sibanyun.entity.inOut.VInOutRecordDetail;
import com.nuoniu.sibanyun.entity.production.*;
import com.nuoniu.sibanyun.mapper.erp.ErpNumberSetMapper;
import com.nuoniu.sibanyun.mapper.production.VProductionFinishMainMapper;
import com.nuoniu.sibanyun.service.crm.ICrmGoodsService;
import com.nuoniu.sibanyun.service.erp.IErpAccountService;
import com.nuoniu.sibanyun.service.erp.IErpNumberSetService;
import com.nuoniu.sibanyun.service.erp.IErpVoucherDesignService;
import com.nuoniu.sibanyun.service.production.IVProductionFinishDetailService;
import com.nuoniu.sibanyun.service.production.IVProductionFinishMainService;
import com.nuoniu.sibanyun.service.utils.ErpUtils;
import com.nuoniu.sibanyun.userThread.UserInfo;
import com.nuoniu.sibanyun.userThread.UserThreadLocal;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 * 生产完工(汇报)单 服务实现类
 * </p>
 *
 * @author 小啊刚
 * @since 2021-02-23
 */
@Service
public class VProductionFinishMainServiceImpl extends ServiceImpl<VProductionFinishMainMapper, VProductionFinishMain> implements IVProductionFinishMainService {

    @Autowired
    private IErpAccountService accountService;
    @Autowired
    private IVProductionFinishDetailService productionFinishDetailService;
    @Autowired
    private ErpNumberSetMapper numberSetMapper;
    @Autowired
    private IErpNumberSetService numberSetService;
    @Autowired
    private IErpVoucherDesignService erpVoucherDesignService;
    @Autowired
    private ICrmGoodsService crmGoodsService;

    @Override
    public void saveOrder(VProductionFinishMain productionFinishMain) {
        Boolean isNewMain = false;
        UserInfo userInfo = UserThreadLocal.get();
        Long mainId = productionFinishMain.getId();
        if(mainId == null) {
            isNewMain = true;
            productionFinishMain.setAccountId(accountService.getCurrentAccountId());
            productionFinishMain.setCompanyId(userInfo.getCompanyId());
            productionFinishMain.setCreateUserId(userInfo.getUserId());
            productionFinishMain.setCreateUserName(userInfo.getRealName());
            productionFinishMain.setVoucherCode(getCode());
            productionFinishMain.setVoucherState(-1);
            productionFinishMain.setCumExecuteQuantity(new BigDecimal(0.0));
            if (null == productionFinishMain.getVoucherState()){
                productionFinishMain.setVoucherState(0);
            }
        }else{
            Long workProcedureCardDetailId = productionFinishMain.getWorkProcedureCardDetailId();
            if(null != workProcedureCardDetailId){
                productionFinishMain.setWorkProcedureCardDetailId(null);
                productionFinishMain.setWorkProcedureCardDetailCode(null);

            }

            VProductionFinishMain oldVProductionFinishMain = getById(mainId);
            if (null == oldVProductionFinishMain)throw new NuoNiuException("修改失败，查询不到记录");
            if(oldVProductionFinishMain.getVoucherState() > 0)throw new NuoNiuException("该单据已审核，不能修改");
            //不可更新字段
            productionFinishMain.setVoucherCode(null);
        }
        // 校验 明细数量
        boolean isOk = productionFinishMain.getOrderDetailList().stream().anyMatch(f -> null == f.getBaseQuantity() || !(f.getBaseQuantity().compareTo(BigDecimal.ZERO) > 0));
        if(isOk)throw new NuoNiuException("明细数量必须大于0");
        List<VProductionFinishDetail> orderDetailList = productionFinishMain.getOrderDetailList();
        //计算 明细物料 总数
        BigDecimal totalQuantity =  orderDetailList.stream().map(VProductionFinishDetail::getBaseQuantity).reduce(BigDecimal.ZERO,BigDecimal::add);
        productionFinishMain.setTotalQuantity(totalQuantity.abs());
        Boolean result = this.saveOrUpdate(productionFinishMain);
        if(result) {
            List<Long> detailIds = new ArrayList<>();
            orderDetailList.forEach(p -> {
                p.setCompanyId(userInfo.getCompanyId());
                p.setAccountId(accountService.getCurrentAccountId());
                p.setOrderId(productionFinishMain.getId().intValue());
                //添加 不删除的明细ID
                if (p.getId() != null) {
                    detailIds.add(p.getId());
                }
            });

            boolean isDealDelete = false;
            if (null != mainId){
                //删除明细
                QueryWrapper wrapper = new QueryWrapper();
                wrapper.eq("order_id", mainId);
                if(detailIds != null && detailIds.size() > 0) {
                    wrapper.notIn("id", detailIds);
                }
                isDealDelete = productionFinishDetailService.remove(wrapper);
            }

            //保存单据明细表
            productionFinishDetailService.saveOrUpdateBatch(orderDetailList);
            // *** 如果 来源订单不为空,校验
            if(null != productionFinishMain.getSourceVoucherId()){
                if(isDealDelete)throw new NuoNiuException("有来源的单据不能删除明细");
                if(!"ProductionWork".equals(productionFinishMain.getSourceVoucherType()))throw new NuoNiuException("生产完工单的来源单，只能是生产订单");

                VoucherMainBo voucherMainBo = new VoucherMainBo();
                BeanUtils.copyProperties(productionFinishMain,voucherMainBo);
                voucherMainBo.setIsNewMain(isNewMain);
                List<VoucherDetailBo> voucherDetailBos = new ArrayList<>();
                orderDetailList.forEach(detail->{
                    VoucherDetailBo voucherDetailBo = new VoucherDetailBo();
                    voucherDetailBos.add(voucherDetailBo);
                    BeanUtils.copyProperties(detail,voucherDetailBo);
                });
                VoucherSearchBo voucherSearchBo = new VoucherSearchBo();
                voucherSearchBo.setSourceVoucherId(productionFinishMain.getSourceVoucherId());
                voucherSearchBo.setSourceVoucherType(productionFinishMain.getSourceVoucherType());
                voucherSearchBo.setVoucherId(productionFinishMain.getId().intValue());
                voucherSearchBo.setVoucherType("ProductionFinish");
                erpVoucherDesignService.calculateSourceVoucher(voucherMainBo,voucherDetailBos,voucherSearchBo);
            }
        }
    }

    @Override
    public void deleteById(Long id) {
        UserInfo userInfo = UserThreadLocal.get();
        VProductionFinishMain productionFinishMain = getById(id);
        if(productionFinishMain == null) {
            throw new NuoNiuException("单据已删除");
        }
        Long workProcedureCardDetailId = productionFinishMain.getWorkProcedureCardDetailId();
        if(null != workProcedureCardDetailId)throw new NuoNiuException("工序汇报单生成的完工单，不可删除；如需删除，请前往工序汇报单进行操作");
        /**************  修改权限 *******************/
        if(!crmGoodsService.isHaveOperationRight(productionFinishMain.getCreateUserId().longValue())){
            throw new NuoNiuException("你没有权限操作该记录");
        }
        BigDecimal cumExecuteQuantity = productionFinishMain.getCumExecuteQuantity();
        if(null != cumExecuteQuantity && cumExecuteQuantity.compareTo(BigDecimal.ZERO) > 0){
            throw new NuoNiuException("单据已生成下一步单据，不能删除");
        }
        String sourceVoucherType = productionFinishMain.getSourceVoucherType();


        List<VProductionFinishDetail> orderDetails   = productionFinishDetailService.getDetailsByOrderId(id);
        //*** 如果 来源订单不为空,校验
        if(null != productionFinishMain.getSourceVoucherId()){
            VoucherMainBo voucherMainBo = new VoucherMainBo();
            BeanUtils.copyProperties(productionFinishMain,voucherMainBo);
            List<VoucherDetailBo> voucherDetailBos = new ArrayList<>();
            orderDetails.forEach(detail->{
                VoucherDetailBo voucherDetailBo = new VoucherDetailBo();
                voucherDetailBos.add(voucherDetailBo);
                BeanUtils.copyProperties(detail,voucherDetailBo);
            });
            VoucherSearchBo voucherSearchBo = new VoucherSearchBo();
            voucherSearchBo.setCalculateType(2);
            voucherSearchBo.setSourceVoucherId(productionFinishMain.getSourceVoucherId());
            voucherSearchBo.setSourceVoucherType(sourceVoucherType);
            voucherSearchBo.setVoucherId(productionFinishMain.getId().intValue());
            voucherSearchBo.setVoucherType("ProductionFinish");
            erpVoucherDesignService.calculateSourceVoucher(voucherMainBo,voucherDetailBos,voucherSearchBo);
        }
        removeById(id);
        productionFinishDetailService.removeByOrderId(id);
    }

    @Override
    public String getCode() {
        Integer currentAccountId = accountService.getCurrentAccountId();
        UserInfo userInfo = UserThreadLocal.get();
        ErpNumberSet numberSet = numberSetMapper.getByCode("ProductionFinish", userInfo.getCompanyId(), currentAccountId);
        String dateStr = numberSet.getMedian() == 1 ? "%Y-%m-%d" : "%Y-%m";
        String code = baseMapper.getNewestCode(userInfo.getCompanyId(), dateStr);
        return numberSetService.getCode(numberSet, code);
    }

    @Override
    public void submit(Long id, Integer status) {
        if(null == id || null == status || (null != status && (status > 0 || status < -1 )))throw new NuoNiuException("参数错误");
        UserInfo userInfo = UserThreadLocal.get();
        VProductionFinishMain main = this.getById(id);
        if( null == main)throw new NuoNiuException("记录不存在");
        //校验状态
        Integer voucherState = main.getVoucherState();
        /**  统一校验 提交状态 */
        ErpUtils.checkSubmitStatus(voucherState,status);
        //提交
        main.setVoucherState(status);
        main.setSubmitDate(LocalDateTime.now());
        main.setSubmitUserId(userInfo.getUserId());
        main.setSubmitUserName(userInfo.getRealName());
        this.updateById(main);
    }

    @Override
    public void examine(Long id, Integer status) {
        if(null == id || null == status ||  (status > 1 || status < 0) )throw new NuoNiuException("参数错误");
        UserInfo userInfo = UserThreadLocal.get();
        VProductionFinishMain oldVProductionFinishMain = getById(id);
        if (null == oldVProductionFinishMain)throw new NuoNiuException("查询不到记录");
        BigDecimal cumExecuteQuantity = oldVProductionFinishMain.getCumExecuteQuantity();
        Integer voucherState = oldVProductionFinishMain.getVoucherState();
        if(null != cumExecuteQuantity && cumExecuteQuantity.compareTo(BigDecimal.ZERO) > 0)throw new NuoNiuException("已经生单，不能做弃审操作");
        /**  统一校验 提交状态 */
        ErpUtils.checkExamineStatus(voucherState,status,cumExecuteQuantity);
        VProductionFinishMain productionFinishMain = new VProductionFinishMain();
        productionFinishMain.setId(id);
        productionFinishMain.setVoucherState(status);
        productionFinishMain.setReviewerDate(LocalDateTime.now());
        productionFinishMain.setReviewerUserId(userInfo.getUserId());
        productionFinishMain.setReviewerUserName(userInfo.getRealName());
        this.updateById(productionFinishMain);
    }

    @Override
    public VProductionFinishMain getByCardDetailId(Long cardDetailId) {
        QueryWrapper<VProductionFinishMain> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("work_procedure_card_detail_id",cardDetailId);
        queryWrapper.last("LIMIT 1");
        VProductionFinishMain one = getOne(queryWrapper);
        return one;
    }

    @Override
    public Long getIdByCardDetailId(Long cardDetailId) {
        QueryWrapper<VProductionFinishMain> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("work_procedure_card_detail_id",cardDetailId);
        queryWrapper.select("id");
        VProductionFinishMain one = getOne(queryWrapper);
        return one.getId();
    }
}
